#include "wo_asyncio.h"
#include "wo_routine.h"
#include "wo_types.h"
#include <fcntl.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <threads.h>
#include <unistd.h>

_Thread_local int epoll_fd;

void wo_wait(int fd, uint32_t events, wo_routine_t *r) {
  struct epoll_event ev = {.events = events, .data = {.ptr = r}};
  if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
    perror("epoll_ctl fail");
    exit(EXIT_FAILURE);
  }
  wo_yield();
}

static int eventloop(void *args) {
  UNUSED(args);
  struct epoll_event events[100];
  for (;;) {
    int nfds = epoll_wait(epoll_fd, events, 100, -1);
    if (nfds == -1) {
      perror("epoll_wait fail");
      exit(EXIT_FAILURE);
    }

    for (int n = 0; n < nfds; n++) {
      wo_routine_t *r = (wo_routine_t *)events[n].data.ptr;
      if (r->state == WO_STATE_IO_WAIT) {
        r->state = WO_STATE_IO_READY;
      }
    }
  }
}

// never return
thrd_t wo_eventloop(void) {
  thrd_t ret = 0;
  epoll_fd = epoll_create1(0);
  if (epoll_fd == -1) {
    perror("epoll create failed");
    exit(EXIT_FAILURE);
  }

  thrd_create(&ret, eventloop, NULL);
  return ret;
}
